package com.boss.salary.service.impl;

import com.boss.common.entity.PageDTO;
import com.boss.common.util.DateUtils;
import com.boss.framework.dto.PaginationDTO;
import com.boss.framework.exception.AppRuntimeException;
import com.boss.salary.constant.SystemDictConstant;
import com.boss.salary.dao.IAgencyInfoDao;
import com.boss.salary.dao.ISalaryBasedataDao;
import com.boss.salary.dao.ISalaryMonthEndDao;
import com.boss.salary.entity.SalaryBasedata;
import com.boss.salary.service.IFormulaManageService;
import com.boss.salary.service.ISalaryBasedataService;
import com.boss.salary.utils.ThreadSalaryBaseDataUpdate;
import com.boss.salary.vo.SalaryMonthEndVO;
import com.boss.sys.utils.SysUtils;
import com.boss.thirteen.dao.ISalaryThirteenMonthDao;
import com.boss.thirteen.dao.ISalaryThirteenMouldDao;
import com.boss.thirteen.entity.SalaryThirteenMonth;
import com.singularsys.jep.JepException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SalaryBasedataServiceImpl implements ISalaryBasedataService {

    /**
     * 引入日志框架常量
     */
    private final static Logger logger = LoggerFactory.getLogger(SalaryBasedataServiceImpl.class);

    @Autowired
    private IFormulaManageService formulaManageService;

    @Autowired
    private ISalaryBasedataDao dao;
    @Autowired
    private ISalaryMonthEndDao salaryMonthEndDao;
    @Autowired
    private IAgencyInfoDao agencyInfoDao;
    @Autowired
    private ISalaryThirteenMonthDao thirteenMonthDao;
    @Autowired
    private ISalaryThirteenMouldDao thirteenMouldDao;

    @Override
    public PageDTO<SalaryBasedata> querySalaryBasedataPage(PaginationDTO paginationDTO,String province) throws AppRuntimeException {
        List<SalaryBasedata> list = dao.querySalaryBasedataPage(paginationDTO,province);
        int total = dao.querySalaryBasedataTotal(province);
        PageDTO<SalaryBasedata> pageDTO = new PageDTO<>();
        pageDTO.setRows(list);
        pageDTO.setTotal(total);
        return pageDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSalaryBasedata(SalaryBasedata salaryBasedata,String province) {
       int i= dao.getMaxCode(province);
       if(i==99){
           throw new AppRuntimeException("已存在工资项过多！");
       }
        salaryBasedata.setId(SysUtils.generateGuid());
        salaryBasedata.setCreateTime(String.valueOf(DateUtils.getCurrentTimeStamp()));
        salaryBasedata.setUpdateTime(String.valueOf(DateUtils.getCurrentTimeStamp()));
        salaryBasedata.setIsDeleted(0);
        salaryBasedata.setSalaryCode("s"+i++);
        dao.saveSalaryBasedata(salaryBasedata);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSalaryBasedata(SalaryBasedata salaryBasedata) {
        salaryBasedata.setUpdateTime(String.valueOf(DateUtils.getCurrentTimeStamp()));
        if(salaryBasedata.getBaseState().equals(SystemDictConstant.DISABLE)){
            salaryMonthEndDao.updateRealAndWages(salaryBasedata,null);
            salaryMonthEndDao.clearSalaryMonthEndByColum(salaryBasedata.getSalaryCode(),null);
        }
        dao.updateSalaryBasedata(salaryBasedata);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitSalaryBasedata(List<SalaryBasedata> salaryBasedataList,String province) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, JepException {

        List<String> closeColumns=new ArrayList<>();
        List<String> notShowColumns=new ArrayList<>();
        String[] salaryCode=new String[]{
                "3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70","71","72","73","74","75","76","77","78","79","80","81","82","83","84","85","86","87","88","89","90","91","92","93","94","95","96","97","98","99","100"
        };
        List<String> salaryCodeList=new ArrayList<>();
        salaryCodeList.addAll(CollectionUtils.arrayToList(salaryCode));
        List<SalaryBasedata> salaryBases=dao.selectAllSalaryCode(province);
        List<String> salaryCodes=salaryBases.stream().map(SalaryBasedata::getSalaryCode).collect(Collectors.toList());
        List<String> salaryNames=salaryBases.stream().map(SalaryBasedata::getSalaryName).collect(Collectors.toList());
        Map<String,String> salaryIdNameMap=salaryBases.stream().collect(Collectors.toMap(SalaryBasedata::getId,SalaryBasedata::getSalaryName));
        boolean flag=true;
        for(String key:salaryCodes){
            String keysub=key.substring(1);
            salaryCodeList.remove(keysub);
            if("1".equals(keysub)){
                flag=false;//表明有实发应发 s1 s2不需要在创建 否则新增s1实发 s2应发
            }
        }
        if(flag){
            SalaryBasedata salaryBasedata =new SalaryBasedata();
            salaryBasedata.setSalaryCode("s1");
            salaryBasedata.setSalaryName("实发工资");
            salaryBasedata.setBaseState(SystemDictConstant.ENABLE);
            salaryBasedata.setIsCompute(SystemDictConstant.IS_TRUE);
            salaryBasedata.setDecimalPlace(2);
            salaryBasedataList.add(salaryBasedata);
            SalaryBasedata salaryBasedata2 =new SalaryBasedata();
            salaryBasedata2.setSalaryCode("s2");
            salaryBasedata2.setSalaryName("应发工资");
            salaryBasedata2.setBaseState(SystemDictConstant.ENABLE);
            salaryBasedata2.setIsCompute(SystemDictConstant.IS_TRUE);
            salaryBasedata2.setDecimalPlace(2);
            salaryBasedataList.add(salaryBasedata2);
        }
        int i=0;
        for(SalaryBasedata salaryBasedata : salaryBasedataList){

            if(SysUtils.isNullOrEmpty(salaryBasedata.getIsShow())){
                salaryBasedata.setIsShow(SystemDictConstant.IS_TRUE);
            }
            String column = salaryBasedata.getSalaryCode();
            if(StringUtils.isEmpty(salaryBasedata.getId())){
                if(salaryNames.contains(salaryBasedata.getSalaryName().trim())){
                    throw new AppRuntimeException("存在同名工资项,请核对！");
                }
                salaryBasedata.setSalaryType("0");
                if(SysUtils.isNullOrEmpty(salaryBasedata.getSalaryCode())) {
                    salaryBasedata.setSalaryCode("s" + salaryCodeList.get(i));
                }
                salaryBasedata.setMofDivCode(province);
                //ID为空即新增
                dao.saveSalaryBasedata(salaryBasedata);
            }else{
                if(salaryBasedata.getSalaryName()!=null&&salaryNames.contains(salaryBasedata.getSalaryName().trim())
                        &&!salaryBasedata.getSalaryName().trim().equals(salaryIdNameMap.get(salaryBasedata.getId()))){
                    //判断当前保存工资项名称存在在已有项中，并且当前id不不等于原工资项名称对应id即存在重复名称工资项不予保存
                    throw new AppRuntimeException("存在同名工资项,请核对！");
                }
                String closeState = "0";//停用状态
                if(closeState.equals(salaryBasedata.getBaseState())){
                    closeColumns.add(column);
                }
                if(0==salaryBasedata.getIsShow()){//隐藏工资项时处理十三月工资相关数据
                    notShowColumns.add(column);
                }
                //ID存在即编辑
                dao.updateSalaryBasedata(salaryBasedata);
            }
            i++;
        }
        if(closeColumns.size()>0){
            logger.info("停用工资项"+closeColumns.toString());
            List<String> agencyIds = agencyInfoDao.selectAllAgencyIdByProvince(province);
            logger.info("停用工资项获取全部单位");
            List<SalaryMonthEndVO> salaryMonthEndVOList = salaryMonthEndDao.selectSalaryMonthEndWithSalaryType(province, agencyIds);
            logger.info("停用工资项获取工资数据");
            Class<?> salaryMonthEndVOClass = SalaryMonthEndVO.class;
            for(String column:closeColumns) {
                for (SalaryMonthEndVO salaryMonthEndVO : salaryMonthEndVOList) {
                    Method setMethod = salaryMonthEndVOClass.getDeclaredMethod("set" + column.substring(0, 1).toUpperCase() + column.substring(1), Double.class);
                    setMethod.invoke(salaryMonthEndVO, Double.parseDouble("0"));
                }
            }
            logger.info("总："+agencyIds.size());
            if(agencyIds.size()>100) {
                for (int j = 0; j < 10; j++) {
                    int step = agencyIds.size() / 10;
                    int index=j==9?agencyIds.size():(j + 1) * step;
                    List<String> ags = agencyIds.subList(j * step, index);
                    List<SalaryMonthEndVO> salaryMonthEnds = salaryMonthEndVOList.stream().filter(smev -> ags.contains(smev.getAgencyId())).collect(Collectors.toList());
                    //创建线程对象
                    ThreadSalaryBaseDataUpdate threadSalaryBaseDataUpdate = new ThreadSalaryBaseDataUpdate();
                    threadSalaryBaseDataUpdate.setAgencyIds(ags);
                    threadSalaryBaseDataUpdate.setProvince(province);
                    threadSalaryBaseDataUpdate.setSalaryMonthEndVOList(salaryMonthEnds);
                    threadSalaryBaseDataUpdate.setFormulaManageService(formulaManageService);
                    threadSalaryBaseDataUpdate.setSalaryMonthEndDao(salaryMonthEndDao);
                    Thread thread = new Thread(threadSalaryBaseDataUpdate);
                    thread.start();
                }
            }else{
                logger.info("停用工资项计算开始");
                salaryMonthEndVOList = formulaManageService.calculateByFormula(province, agencyIds, salaryMonthEndVOList);
                logger.info("停用工资项计算结束");
                salaryMonthEndDao.batchUpdateSalaryMonthEnd(salaryMonthEndVOList);
                logger.info("停用工资保存修改后数据完成");
            }
            try {
                updateThirteenMonth(closeColumns,province);
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
        notShowColumns.removeAll(closeColumns);
        if(notShowColumns.size()>0){
            logger.info("隐藏工资项"+notShowColumns.toString());
            try {
                updateThirteenMonth(notShowColumns,province);
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSalaryBasedata(String ids) {
            dao.deleteSalaryBasedata(ids);
    }

    @Override
    public List<SalaryBasedata> querySalaryBaseDataInfo(Map<String, Object> queryParam) {
        return dao.querySalaryBaseDataInfo(queryParam);
    }

    @Override
    public List<SalaryBasedata> queryBgtSalaryBaseDataInfo(Map<String, Object> queryParam) {
        return dao.queryBgtSalaryBaseDataInfo(queryParam);
    }

    @Override
    public List<SalaryBasedata> queryStandardBasedataInfo(Map<String, Object> queryParam) {
        return dao.queryStandardBasedataInfo(queryParam);
    }

    /**
     * 修改工资项停用隐藏时处理十三月工资数据
     * @param columns
     * @param province
     * @throws Exception
     */
    private void updateThirteenMonth(List<String> columns,String province) throws Exception{
        String year= String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
        List<Map<String, Object>> moulds=thirteenMouldDao.selectSalaryThirteenMould(province,year);
        if(!CollectionUtils.isEmpty(moulds)) {
            for(String column:columns) {
                for (Map<String, Object> mould : moulds) {
                    mould.put("salaryCodes",mould.get("salary_codes").toString().replace("," + column, ""));
                    mould.put("month",mould.get("mould_month"));
                    mould.put("mouldKey",mould.get("biz_key"));
                    mould.put("meritPayCode",mould.get("merit_pay_code"));
                }
            }
            thirteenMouldDao.batchUpdateSalaryThirteenMould(moulds);
            Map<String, Object> params = new HashMap<>();
            params.put("province", province);
            List<SalaryThirteenMonth> stms = thirteenMonthDao.selectSalaryThirteenMonth(params);
            if(!CollectionUtils.isEmpty(stms)) {
                Class<?> thirteenMonthClass = SalaryThirteenMonth.class;
                for (String column : columns) {
                    for (SalaryThirteenMonth stm : stms) {
                        Method setMethod = thirteenMonthClass.getDeclaredMethod("set" + column.substring(0, 1).toUpperCase() + column.substring(1), Double.class);
                        setMethod.invoke(stm, Double.parseDouble("0"));
                    }
                }
                for (SalaryThirteenMonth stm : stms) {
                    BigDecimal s1 = new BigDecimal("0");
                    for (int j = 3; j <= 100; j++) {
                        Class<?> clazz = stm.getClass();
                        Method getMethod = clazz.getDeclaredMethod("getS" + j);
                        String value = getMethod.invoke(stm) == null ? "0" : getMethod.invoke(stm).toString();
                        s1 = s1.add(new BigDecimal(value));
                    }
                    s1 = s1.multiply(new BigDecimal(stm.getPercent())).setScale(2, BigDecimal.ROUND_HALF_UP);
                    ;
                    stm.setS1(s1.doubleValue());
                }
                try {
                    thirteenMonthDao.batchUpdateSalaryThirteenMonth(stms);
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
        }
    }

}
